package cn.seaboot.commons.file;


import org.springframework.lang.Nullable;
import org.springframework.util.InvalidMimeTypeException;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;

import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Map;

/**
 * 媒体类型
 * <p>
 * 选自 spring 的源代码，google 提供的工具包中也有相同的封装。
 * <p>
 * 推荐大家用的时候，自己复制一份，因为不论是谁封装的，在实际使用过程中，总会缺几个。
 *
 * @author Mr.css
 * @version 2025-04-03 17:26
 */
public class MediaType extends MimeType {
	private static final long serialVersionUID = -4333913943978767268L;
	public static final MediaType ALL;
    public static final String ALL_VALUE = "*/*";

    public static final MediaType APPLICATION_ZIP;
    public static final String APPLICATION_ZIP_VALUE = "application/zip";

    public static final MediaType APPLICATION_ATOM_XML;
    public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml";
    public static final MediaType APPLICATION_FORM_URLENCODED;
    public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
    public static final MediaType APPLICATION_JSON;
    public static final String APPLICATION_JSON_VALUE = "application/json";
    public static final MediaType APPLICATION_JSON_UTF8;
    public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
    public static final MediaType APPLICATION_OCTET_STREAM;
    public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";

    public static final MediaType APPLICATION_PDF;
    public static final String APPLICATION_PDF_VALUE = "application/pdf";
    public static final MediaType APPLICATION_DOC;
    public static final String APPLICATION_DOC_VALUE = "application/msword";
    public static final MediaType APPLICATION_XLS;
    public static final String APPLICATION_XLS_VALUE = "application/vnd.ms-excel";
    public static final MediaType APPLICATION_DOCX;
    public static final String APPLICATION_DOCX_VALUE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    public static final MediaType APPLICATION_XLSX;
    public static final String APPLICATION_XLSX_VALUE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

    public static final MediaType APPLICATION_PROBLEM_JSON;
    public static final String APPLICATION_PROBLEM_JSON_VALUE = "application/problem+json";
    public static final MediaType APPLICATION_PROBLEM_JSON_UTF8;
    public static final String APPLICATION_PROBLEM_JSON_UTF8_VALUE = "application/problem+json;charset=UTF-8";
    public static final MediaType APPLICATION_PROBLEM_XML;
    public static final String APPLICATION_PROBLEM_XML_VALUE = "application/problem+xml";
    public static final MediaType APPLICATION_RSS_XML;
    public static final String APPLICATION_RSS_XML_VALUE = "application/rss+xml";
    public static final MediaType APPLICATION_STREAM_JSON;
    public static final String APPLICATION_STREAM_JSON_VALUE = "application/stream+json";
    public static final MediaType APPLICATION_XHTML_XML;
    public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml";
    public static final MediaType APPLICATION_XML;
    public static final String APPLICATION_XML_VALUE = "application/xml";

    public static final MediaType IMAGE_GIF;
    public static final String IMAGE_GIF_VALUE = "image/gif";
    public static final MediaType IMAGE_JPEG;
    public static final String IMAGE_JPEG_VALUE = "image/jpeg";
    public static final MediaType IMAGE_PNG;
    public static final String IMAGE_PNG_VALUE = "image/png";
    public static final MediaType MULTIPART_FORM_DATA;
    public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
    public static final MediaType TEXT_EVENT_STREAM;

    public static final String TEXT_EVENT_STREAM_VALUE = "text/event-stream";
    public static final MediaType TEXT_HTML;
    public static final String TEXT_HTML_VALUE = "text/html";
    public static final MediaType TEXT_MARKDOWN;
    public static final String TEXT_MARKDOWN_VALUE = "text/markdown";
    public static final MediaType TEXT_PLAIN;
    public static final String TEXT_PLAIN_VALUE = "text/plain";
    public static final MediaType TEXT_XML;
    public static final String TEXT_XML_VALUE = "text/xml";

    private static final String PARAM_QUALITY_FACTOR = "q";

    static {
        ALL = valueOf(ALL_VALUE);

        APPLICATION_ZIP = valueOf(APPLICATION_ZIP_VALUE);
        APPLICATION_OCTET_STREAM = valueOf(APPLICATION_OCTET_STREAM_VALUE);
        APPLICATION_FORM_URLENCODED = valueOf(APPLICATION_FORM_URLENCODED_VALUE);

        APPLICATION_JSON = valueOf(APPLICATION_JSON_VALUE);
        APPLICATION_JSON_UTF8 = valueOf(APPLICATION_JSON_UTF8_VALUE);
        APPLICATION_STREAM_JSON = valueOf(APPLICATION_STREAM_JSON_VALUE);

        APPLICATION_XML = valueOf(APPLICATION_XML_VALUE);
        APPLICATION_RSS_XML = valueOf(APPLICATION_RSS_XML_VALUE);
        APPLICATION_ATOM_XML = valueOf(APPLICATION_ATOM_XML_VALUE);
        APPLICATION_XHTML_XML = valueOf(APPLICATION_XHTML_XML_VALUE);

        APPLICATION_PDF = valueOf(APPLICATION_PDF_VALUE);
        APPLICATION_DOC = valueOf(APPLICATION_DOC_VALUE);
        APPLICATION_XLS = valueOf(APPLICATION_XLS_VALUE);
        APPLICATION_DOCX = valueOf(APPLICATION_DOCX_VALUE);
        APPLICATION_XLSX = valueOf(APPLICATION_XLSX_VALUE);

        APPLICATION_PROBLEM_XML = valueOf(APPLICATION_PROBLEM_XML_VALUE);
        APPLICATION_PROBLEM_JSON = valueOf(APPLICATION_PROBLEM_JSON_VALUE);
        APPLICATION_PROBLEM_JSON_UTF8 = valueOf(APPLICATION_PROBLEM_JSON_UTF8_VALUE);

        IMAGE_GIF = valueOf(IMAGE_GIF_VALUE);
        IMAGE_PNG = valueOf(IMAGE_PNG_VALUE);
        IMAGE_JPEG = valueOf(IMAGE_JPEG_VALUE);
        MULTIPART_FORM_DATA = valueOf(MULTIPART_FORM_DATA_VALUE);

        TEXT_XML = valueOf(TEXT_XML_VALUE);
        TEXT_HTML = valueOf(TEXT_HTML_VALUE);

        TEXT_PLAIN = valueOf(TEXT_PLAIN_VALUE);
        TEXT_MARKDOWN = valueOf(TEXT_MARKDOWN_VALUE);
        TEXT_EVENT_STREAM = valueOf(TEXT_EVENT_STREAM_VALUE);
    }

    /**
     * Create a new {@code MediaType} for the given primary type.
     * <p>The {@linkplain #getSubtype() subtype} is set to "&#42;", parameters empty.
     *
     * @param type the primary type
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(String type) {
        super(type);
    }

    /**
     * Create a new {@code MediaType} for the given primary type and subtype.
     * <p>The parameters are empty.
     *
     * @param type    the primary type
     * @param subtype the subtype
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(String type, String subtype) {
        super(type, subtype, Collections.emptyMap());
    }

    /**
     * Create a new {@code MediaType} for the given type, subtype, and character set.
     *
     * @param type    the primary type
     * @param subtype the subtype
     * @param charset the character set
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(String type, String subtype, Charset charset) {
        super(type, subtype, charset);
    }

    /**
     * Create a new {@code MediaType} for the given type, subtype, and quality value.
     *
     * @param type         the primary type
     * @param subtype      the subtype
     * @param qualityValue the quality value
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(String type, String subtype, double qualityValue) {
        this(type, subtype, Collections.singletonMap(PARAM_QUALITY_FACTOR, Double.toString(qualityValue)));
    }

    /**
     * Copy-constructor that copies the type, subtype and parameters of the given
     * {@code MediaType}, and allows to set the specified character set.
     *
     * @param other   the other media type
     * @param charset the character set
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     * @since 4.3
     */
    public MediaType(MediaType other, Charset charset) {
        super(other, charset);
    }

    /**
     * Copy-constructor that copies the type and subtype of the given {@code MediaType},
     * and allows for different parameter.
     *
     * @param other      the other media type
     * @param parameters the parameters, may be {@code null}
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(MediaType other, @Nullable Map<String, String> parameters) {
        super(other.getType(), other.getSubtype(), parameters);
    }

    /**
     * Create a new {@code MediaType} for the given type, subtype, and parameters.
     *
     * @param type       the primary type
     * @param subtype    the subtype
     * @param parameters the parameters, may be {@code null}
     * @throws IllegalArgumentException if any of the parameters contain illegal characters
     */
    public MediaType(String type, String subtype, @Nullable Map<String, String> parameters) {
        super(type, subtype, parameters);
    }

    /**
     * Parse the given String value into a {@code MediaType} object,
     * with this method name following the 'valueOf' naming convention
     * (as supported by {@link org.springframework.core.convert.ConversionService}.
     *
     * @param value the string to parse
     * @throws IllegalArgumentException if the media type value cannot be parsed
     * @see #parseMediaType(String)
     */
    public static MediaType valueOf(String value) {
        return parseMediaType(value);
    }

    /**
     * Parse the given String into a single {@code MediaType}.
     *
     * @param mediaType the string to parse
     * @return the media type
     * @throws IllegalArgumentException if the media type value cannot be parsed
     */
    public static MediaType parseMediaType(String mediaType) {
        MimeType type;
        try {
            type = MimeTypeUtils.parseMimeType(mediaType);
        } catch (InvalidMimeTypeException ex) {
            throw new IllegalArgumentException(ex);
        }
        try {
            return new MediaType(type.getType(), type.getSubtype(), type.getParameters());
        } catch (IllegalArgumentException ex) {
            throw new IllegalArgumentException(mediaType, ex);
        }
    }
}
